package com.example.demo.service.exam.impl;

import com.example.demo.base.config.auth.UserInfoShareHolder;
import com.example.demo.base.login.dto.UserCache;
import com.example.demo.domain.CombineClause;
import com.example.demo.domain.SingleClause;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.exam.ExamUserAnswerOption;
import com.example.demo.domain.exam.UserExamAns;
import com.example.demo.enums.QuestionType;
import com.example.demo.exception.ExceptionUtils;
import com.example.demo.mapper.UserExamAnswerMapper;
import com.example.demo.service.ExamUserAnswerOptionService;
import com.example.demo.service.exam.ExamUserScoreService;
import com.example.demo.service.exam.ExamUserSingleQuesScoreService;
import com.example.demo.service.impl.BaseServiceImpl;
import com.example.demo.service.exam.UserExamAnswerService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class UserExamAnswerServiceImpl extends BaseServiceImpl<UserExamAnswerMapper, UserExamAns> implements UserExamAnswerService {

    private final UserExamAnswerMapper mapper;

    private final ExamUserAnswerOptionService examUserAnswerOptionService;

    private final ExamUserScoreService examUserScoreService;

    private final ExamUserSingleQuesScoreService examUserSingleQuesScoreService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void insertList(List<UserExamAns> userExamAnswerList) {
        UserCache userInfo = UserInfoShareHolder.getUserInfo();
        User user = userInfo.getUser();
        Long userId = user.getId();
        if (CollectionUtils.isEmpty(userExamAnswerList)) {
            return;
        }
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        List<ExamUserAnswerOption> options = new ArrayList<>();
        userExamAnswerList.forEach(e -> {
            e.setUserId(userId);
            this.checkAnswer(e);
            e.setCreateTime(currentTime);
        });
        this.saveBatch(userExamAnswerList);

        userExamAnswerList.stream().filter(e -> e.getQuestionType() != QuestionType.PROGRAMMING_QUESTION).forEach(e -> {
            List<ExamUserAnswerOption> option = e.getOptions();
            option.forEach(o -> o.setAnswerId(e.getId()));
        });
        examUserAnswerOptionService.insertList(options);
    }

    @Override
    public List<UserExamAns> getExamAns(Long examId, Long userId) {
        Optional.ofNullable(examId).orElseThrow(() -> ExceptionUtils.exception("考试标识不能为空"));
        Optional.ofNullable(userId).orElseThrow(() -> ExceptionUtils.exception("用户标识不能为空"));
        return mapper.getByExamUserId(examId, userId);
    }

    @Override
    public void saveOrUpdateProgrammingQuestion(UserExamAns entity) {
        checkAnswer(entity);
        super.saveOrUpdate(entity);
    }

    @Override
    public UserExamAns getByExamUserQuestionId(Long examId, Long userId, Long questionId) {
        Optional.ofNullable(examId).orElseThrow(() -> ExceptionUtils.exception("考试标识不能为空"));
        Optional.ofNullable(userId).orElseThrow(() -> ExceptionUtils.exception("用户标识不能为空"));
        Optional.ofNullable(questionId).orElseThrow(() -> ExceptionUtils.exception("问题标识不能为空"));
        return mapper.getByExamUserQuestionId(examId, userId, questionId);
    }

    private void checkAnswer(UserExamAns answer) {
        Long paperId = answer.getPaperId();
        Long examId = answer.getExamId();
        Long questionId = answer.getQuestionId();
        if (paperId == null) {
            throw ExceptionUtils.exception("试卷标识不能为空");
        }
        if (examId == null) {
            throw ExceptionUtils.exception("考试标识不能为空");
        }
        if (questionId == null) {
            throw ExceptionUtils.exception("题目标识不能为空");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByExamUserId(Long examId, Long userId) {
        Optional.ofNullable(examId).orElseThrow(() -> ExceptionUtils.exception("考试标识不能为空"));
        Optional.ofNullable(userId).orElseThrow(() -> ExceptionUtils.exception("用户标识不能为空"));
        List<Long> answerIds = super.selectList(CombineClause.and(
                SingleClause.equal("user_id", userId),
                SingleClause.equal("exam_id", examId)
        )).stream().map(UserExamAns::getId).collect(Collectors.toList());
        if (!answerIds.isEmpty()) {
            mapper.deleteBatchIds(answerIds);
        }
        // 删除选项
        examUserAnswerOptionService.deleteByAnswerIds(answerIds);
        // 删除总分
        examUserScoreService.deleteByExamUserId(examId, userId);
        // 删除单道题得分
        examUserSingleQuesScoreService.deleteByExamUserId(examId, userId);
    }

    @Override
    public List<UserExamAns> getExamAnsByExamId(Long examId) {
        Optional.ofNullable(examId).orElseThrow(() -> ExceptionUtils.exception("考试标识不能为空"));
        return mapper.getByExamId(examId);
    }

}
